home *** CD-ROM | disk | FTP | other *** search
- /*
- ** qsprintf()
- ** Copyright (C) 1988, 1989, William B. McCormick
- ** Released to public domain on 01 February 1989.
- **
- ** Reentrant sprintf() replacement. Quick-and-dirty but duplicates most
- ** of the sprintf() functionality.
- **
- ** History:
- ** 07/28/88 William B. McCormick
- ** Quick printf() for OS/2 multi-threaded programs.
- ** 02/01/89 William B. McCormick
- ** Changed to sprintf(). Added '*' specification. Released
- ** to public domain.
- **
- ** Properly formats:
- ** % [flags] [width ] [.precision] [size] type
- ** flags:
- ** - left justify the result within field.
- ** 0 pad with '0' instead of ' '
- ** width:
- ** Controls the minimum # of characters printed. If value is
- ** less than specified width, padding is added. The width
- ** may be '*', in which case an integer argument from the
- ** argument list supplies the value.
- ** precision:
- ** Specifies the maximum # of characters printed. The precision
- ** may be '*', in which case an integer argument from the
- ** argument list supplies the value.
- ** size:
- ** F Specifies 's' is FAR
- ** N Specifies 's' is NEAR
- ** l Specifies 'd', 'x', 'u' is long
- ** B Followed by integer (or '*') from 2-36. Specifies
- ** base of number to be printed with 'd', 'i', or 'u'.
- ** type:
- ** s string
- ** d signed integer
- ** i signed integer
- ** u unsigned integer
- ** x unsigned hexadecimal integer ('abcdef')
- ** n Number of characters written to destination so far
- ** is stored in the integer whose address is given as
- ** the argument
- */
-
- #include <stdlib.h>
- #include <stdarg.h>
- #include <limits.h>
-
-
- /* comment out these lines for strict ANSI compatibility */
- #define FAR far
- #define NEAR near
-
-
- /* prototype */
- int qsprintf( char *dest, const char *fmt, ... );
-
-
- #define TRUE 1
- #define FALSE 0
-
- #ifndef isdigit
- # define isdigit(c) ((c)>='0' && (c)<='9')
- #endif
-
-
- #define w_char( dest, ch ) (*(dest)++ = ch)
- #define w_str( dest, str, len ) for ( ; (len)>0; (len)--, (str)++ ) \
- w_char( (dest), *(str) )
-
-
- static void
- w_string( char **pdest,
- register const char FAR *str,
- int minlen,
- int maxlen,
- char fill )
- {
- unsigned count, c2;
- register const char FAR *p;
- char *dest;
- dest = *pdest;
-
- count = 0;
- p = str;
- while ( *p++ )
- if ( ++count == maxlen )
- break;
-
- if ( minlen > 0 ) {
- for ( ; minlen>count; --minlen )
- w_char( dest, fill );
- }
-
- c2 = count;
- w_str( dest, str, c2 );
-
- if ( minlen < 0 ) {
- for ( minlen=-minlen; minlen>count; --minlen )
- w_char( dest, fill );
- }
- *pdest = dest;
- }
-
-
- static char
- get_int( va_list *parg, const char **pp, int *vp )
- {
- register const char *p;
- register int val;
- int sign;
- char firstc;
- p = *pp;
-
- if ( *p=='-' ) {
- ++p;
- sign = -1;
- }
- else
- sign = 1;
- firstc = *p;
-
- if ( *p=='0' ) /* skip zero in case '0*' */
- ++ p;
-
- if ( *p=='*' ) { /* get the value */
- ++ p;
- val = va_arg( *parg, int );
- }
- else {
- val = 0;
- for ( ; isdigit(*p); p++ )
- val = val * 10 + *p - '0';
- }
- *vp = val * sign;
- *pp = p;
- return firstc;
- }
-
-
-
-
- int cdecl
- qsprintf( char *dest, const char *fmt, ... )
- {
- va_list arg;
- register const char *reg_p;
- const char *auto_p;
- char buf[ CHAR_BIT * sizeof(long) + 1 ];
- int val, val2;
- int base;
- int islong, isfar, isnear;
- char fill;
- char *org_dest;
-
- org_dest = dest;
-
- va_start(arg,fmt);
- reg_p = fmt;
-
- for ( ;*reg_p; reg_p++ ) {
- if ( *reg_p=='%' ) {
- isnear = isfar = islong = FALSE;
- val = val2 = 0;
- base = 10;
- fill = ' ';
- auto_p = reg_p + 1;
- if ( get_int( &arg, &auto_p, &val ) == '0' )
- fill = '0';
- if ( *auto_p=='.' ) {
- ++auto_p;
- (void) get_int( &arg, &auto_p, &val2 );
- }
- reg_p = auto_p-1;
- next_fmt:
- switch ( *++reg_p ) {
-
- case 'l':
- islong = TRUE;
- goto next_fmt;
-
- case 'F':
- isfar = TRUE;
- goto next_fmt;
-
- case 'N':
- isnear = TRUE;
- goto next_fmt;
-
- case 'B':
- auto_p = reg_p+1;
- (void) get_int( &arg, &auto_p, &base );
- reg_p = auto_p-1;
- goto next_fmt;
-
- case 'n':
- *va_arg( arg, int * ) = dest - org_dest;
- break;
-
- case 's':
- w_string( &dest,
- isfar ?
- va_arg(arg,const char FAR *) :
- (isnear ?
- (const char FAR *)va_arg(arg,
- const char NEAR *) :
- (const char FAR *)va_arg(arg, const char *)),
- val,
- val2,
- fill );
- break;
-
- case 'u':
- w_string( &dest,
- ltoa( islong ?
- va_arg(arg,unsigned long) :
- (unsigned long)va_arg(arg,unsigned),
- buf,
- base ),
- val,
- INT_MAX,
- fill );
- break;
-
- case 'd':
- case 'i':
- w_string( &dest,
- ltoa( islong ?
- va_arg(arg,long) :
- (long) va_arg(arg,int),
- buf,
- base ),
- val,
- INT_MAX,
- fill );
- break;
-
- case 'x':
- w_string( &dest,
- ltoa( islong ?
- va_arg(arg,long) :
- (long) va_arg(arg,int),
- buf,
- 16 ),
- val,
- INT_MAX,
- fill );
- break;
-
- default:
- w_char( dest, *reg_p );
- }
- }
- else {
- w_char( dest, *reg_p );
- }
- }
- w_char( dest, '\0' );
- return dest - org_dest - 1; /* length of string */
- }
-
-
-
-
-
-